<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- 
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License. 
-->
<html>
<head>
    <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css">
    <style type="text/css">
        .dp-highlighter {
            width:95% !important;
        }
    </style>
    <style type="text/css">
        .footer {
            background-image:      url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif');
            background-repeat:     repeat-x;
            background-position:   left top;
            padding-top:           4px;
            color:                 #666;
        }
    </style>
    <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' />
    <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' />
    <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script>
    <script type="text/javascript">
        SyntaxHighlighter.defaults['toolbar'] = false;
        SyntaxHighlighter.all();
    </script>
    <script type="text/javascript" language="javascript">
        var hide = null;
        var show = null;
        var children = null;

        function init() {
            /* Search form initialization */
            var form = document.forms['search'];
            if (form != null) {
                form.elements['domains'].value = location.hostname;
                form.elements['sitesearch'].value = location.hostname;
            }

            /* Children initialization */
            hide = document.getElementById('hide');
            show = document.getElementById('show');
            children = document.all != null ?
                    document.all['children'] :
                    document.getElementById('children');
            if (children != null) {
                children.style.display = 'none';
                show.style.display = 'inline';
                hide.style.display = 'none';
            }
        }

        function showChildren() {
            children.style.display = 'block';
            show.style.display = 'none';
            hide.style.display = 'inline';
        }

        function hideChildren() {
            children.style.display = 'none';
            show.style.display = 'inline';
            hide.style.display = 'none';
        }
    </script>
    <title>Handling File Uploads</title>
</head>
<body onload="init()">
<table border="0" cellpadding="2" cellspacing="0" width="100%">
    <tr class="topBar">
        <td align="left" valign="middle" class="topBarDiv" align="left" nowrap>
            &nbsp;<a href="home.html">Home</a>&nbsp;&gt;&nbsp;<a href="faqs.html">FAQs</a>&nbsp;&gt;&nbsp;<a href="cookbook.html">Cookbook</a>&nbsp;&gt;&nbsp;<a href="handling-file-uploads.html">Handling File Uploads</a>
        </td>
        <td align="right" valign="middle" nowrap>
            <form name="search" action="https://www.google.com/search" method="get">
                <input type="hidden" name="ie" value="UTF-8" />
                <input type="hidden" name="oe" value="UTF-8" />
                <input type="hidden" name="domains" value="" />
                <input type="hidden" name="sitesearch" value="" />
                <input type="text" name="q" maxlength="255" value="" />
                <input type="submit" name="btnG" value="Google Search" />
            </form>
        </td>
    </tr>
</table>

<div id="PageContent">
    <div class="pageheader" style="padding: 6px 0px 0px 0px;">
        <!-- We'll enable this once we figure out how to access (and save) the logo resource -->
        <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"-->
        <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div>
        <div style="margin: 0px 10px 8px 10px"  class="pagetitle">Handling File Uploads</div>

        <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;">
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13885">
                <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13885">Edit Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">
                <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a>
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13885">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13885">Add Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13885">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add News"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13885">Add News</a>
        </div>
    </div>

    <div class="pagecontent">
        <div class="wiki-content">
            <div id="ConfluenceContent"><p>The framework comes with built in file upload support. Uploading a file is simple. When FilterDispatcher receives a request, it checks to see if the request contains multipart content. If it does the dispatcher creates a MultipartWrapperRequest. This wrapper handles receiving the file and saving to disk. It is important for the Action programmer to check to see if any errors occured during processing. Three properties can be set that effect file uploading.</p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Ensure you have the necessary file upload libraries in your application. If using the default file upload parser, Commons Fileupload and its dependencies should be in your application's classpath.</p></div></div><h2 id="HandlingFileUploads-Properties">Properties</h2><p>Properties can be set by putting a <code>struts.properties</code> file in <code>WEB-INF/classes</code>. Any property found in the properties file will override the default value.</p><ol><li><code>struts.multipart.parser</code> - This property should be set to a class that extends MultiPartRequest. Currently, the framework ships with the Jakarta FileUpload implementation.</li><li><code>struts.multipart.saveDir</code> - The directory where the uploaded files will be placed. If this property is not set it defaults to <code>javax.servlet.context.tempdir</code>.</li><li><code>struts.multipart.maxSize</code> - The maximum file size in bytes to allow for upload. This helps prevent system abuse by someone uploading lots of large files. The default value is 2 Megabytes and can be set as high as 2 Gigabytes (higher if you want to edit the Pell multipart source but you really need to rethink things if you need to upload files larger then 2 Gigabytes!) If you are uploading more than one file on a form the maxSize applies to the combined total, not the individual file sizes.</li></ol><p>If you're happy with the defaults, there is no need to put any of the properties in <code>struts.properties</code>.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>struts.properties</b></div><div class="codeContent panelContent pdl">
<pre class="brush: text; gutter: false; theme: Default" style="font-size:12px;"># put the uploaded files in /tmp. My application will move them to their
# final destination
struts.multipart.saveDir=/tmp
</pre>
</div></div><p>Note, while you can set these properties to new values at runtime the MultiPartRequestWrapper is created and the file handled before your Action code is called. So if you want to change values you must do so before this Action.</p><h2 id="HandlingFileUploads-SampleForm">Sample Form</h2><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;%@ taglib uri="action2" prefix="s" %&gt;

&lt;html&gt;
  &lt;head&gt;
   &lt;title&gt;File Upload Test&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;File Upload&lt;/h1&gt;

    &lt;form action="FileUpload.action" method="POST" enctype="multipart/form-data"&gt;

    &lt;center&gt;
      &lt;table width="350" border="0" cellpadding="3" cellspacing="0"&gt;
      &lt;tr&gt;
        &lt;td colspan="2"&gt;&lt;input type="file" name="FileName" value="Browse..." size="50"/&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td colspan="2" align="center"&gt;
          &lt;input type="submit" value="Submit"&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;/table&gt;
    &lt;/center&gt;
  &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
</div></div><p>That's all you have to do to upload a file. No coding required, the file will be placed in the default directory. However, that leaves us with no error checking among other things. So let's add some code to the Action.</p><h2 id="HandlingFileUploads-FileUploadAction">File Upload Action</h2><p>Before the Action method is called the dispatcher will upload the file. Then we can get access to information about the file from MultiPartRequestWrapper.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>FileUploadAction.java</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">MultiPartRequestWrapper multiWrapper =
		(MultiPartRequestWrapper) ServletActionContext.getRequest();
</pre>
</div></div><p>The first thing you should always do is check for errors. If there were any, there's no point in continuing, most methods will return null. Unfortunately, currently there is no easy way to distinguish what error occured making it more difficult to route to different error pages.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">if (multiWrapper.hasErrors()) {
  Collection errors = multiWrapper.getErrors();
  Iterator i = errors.iterator();
  while (i.hasNext()) {
    addActionError((String) i.next());
  }
  return ERROR;
}
</pre>
</div></div><p>Now get the input tag name for the uploaded file and use that to get information on the transfer. Since you can upload multiple files (just add multiple input tags) at a time <code>getFileNames</code> returns an Enumeration of the names.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">Enumeration e = multiWrapper.getFileNames();

while (e.hasMoreElements()) {
   // get the value of this input tag
   String inputValue = (String) e.nextElement();

   // get the content type
   String contentType = multiWrapper.getContentType(inputValue);

   // get the name of the file from the input tag
   String fileName = multiWrapper.getFilesystemName(inputValue);

   // Get a File object for the uploaded File
   File file = multiWrapper.getFile(inputValue);

   // If it's null the upload failed
   if (file == null) {
      addActionError("Error uploading: " + multiWrapper.getFilesystemName(inputValue));
   }

   // Do additional processing/logging...
}
</pre>
</div></div><h2 id="HandlingFileUploads-FurtherImprovements">Further Improvements</h2><p>Code above may be packed into one nice reusable component (Interceptor) that handles 90% of all typical file upload tasks. And Action does not know anything about web-app and just gets its files. Neat.</p><p><img class="emoticon emoticon-light-on" src="https://cwiki.apache.org/confluence/s/en_GB/5982/f2b47fb3d636c8bc9fd0b11c0ec6d0ae18646be7.1/_/images/icons/emoticons/lightbulb_on.png" data-emoticon-name="light-on" alt="(lightbulb)"> For more, see the <a shape="rect" href="file-upload-interceptor.html">File Upload Interceptor</a></p></div>
        </div>

        
    </div>
</div>
<div class="footer">
    Generated by CXF SiteExporter
</div>
</body>
</html>
